State Flow 是從 Shared Flow 繼承而來的,跟 Shared Flow 不同的地方在於它是有初始值的,至少會重播一個值給訂閱者,所以它最少會記得一個值。
這邊的值,就代表儲存的狀態 (State),所以我們如果要在多個訂閱者中發送狀態,我們就可以使用 State Flow。
既然是繼承 Shared flow,那麼它也是 Hot flow,也不會自己停下來。在 State 中有一個可以更新的 value
,這個值就是實際 State 的值。
class Day23 {
private val _state = MutableStateFlow(false)
val state = _state.asStateFlow()
suspend fun updateResult(value: Boolean) {
delay(200)
_state.update { value }
}
}
在這個類別中,我們一樣採用的是限制在這個類別裡更新,讓 MutableStateFlow
負責更新,對外只有讓外面的使用者使用 StateFlow
,而這邊的 StateFlow 我們是使用 MutableStateFlow 的 asStateFlow()
來將 MutableStateFlow 轉換成 StateFlow。
而另外我們建立一個函式 updateResult
可以更新 MutableStateFlow 的值,其中更新 MutableStateFlow 值的方式是使用 update{}
。
update 函式的內容我們來看一下
public inline fun <T> MutableStateFlow<T>.update(function: (T) -> T) {
while (true) {
val prevValue = value
val nextValue = function(prevValue)
if (compareAndSet(prevValue, nextValue)) {
return
}
}
}
在這個函式中我們注意到它會一直執行帶進來的 lambda,並將 lambda 的回傳值作為 nextValue ,當現在的值以及 nextValue 相同時,就會跳出這個無窮迴圈,否則將會一直在這個迴圈裡更新現在的值。
所以我們知道,當更新 StateFlow 的 value 時,如果 value 已經與現在的 value 一樣,那麼就不會再次寫入,也就是説,當現在的狀態與更新狀態一樣時,就不會有任何動作。
執行它看看:
fun main() = runBlocking {
val day23 = Day23()
val state1 = day23.state
state1.collect {
println("$it")
day23.updateResult(true)
}
println("done")
}
false
true
→ 由結果我們可以得知,collect 會一直去監聽 StateFlow 的狀態值,當狀態有改變的時候,就會立即跑進 collect 這個 lambda 中,接著就會繼續等待,因為它是一個 Hot Flow。所以 "done" 在這個例子下就永遠都不會被呼叫了。
--請接續下篇--
有興趣的讀者歡迎參考:https://coroutine.kotlin.tips/
天瓏書局